package cn.org.rookie.jeesdp.core;


import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.*;

@SuppressWarnings("unchecked")
public class Record extends LinkedHashMap<String, Object> implements Serializable {

    public static Record describe(Object entity) {

        Record record = new Record();
        if (entity instanceof Map<?, ?> map) {
            map.forEach((key, value) -> {
                if (key instanceof String keyString) {
                    record.put(keyString, value);
                } else {
                    throw new RuntimeException("键必须为字符串类型");
                }
            });
        } else {
            for (Field field : getAllField(entity.getClass())) {
                try {
                    record.put(field.getName(), field.get(entity));
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return record;
    }

    private static List<Field> getAllField(Class<?> type) {
        List<Field> fields = new ArrayList<>(Arrays.asList(type.getDeclaredFields()));
        Class<?> superclass = type.getSuperclass();
        if (!superclass.equals(Object.class)) {
            fields.addAll(0, getAllField(superclass));
        }
        return fields;
    }

    public <T> T get(String name, Class<T> type) {
        return (T) get(name);
    }

    public String getString(String name) {
        return get(name, String.class);
    }

    public Boolean getBoolean(String name) {
        return get(name, Boolean.class);
    }

    public Short getShort(String name) {
        return get(name, Short.class);
    }

    public char getChar(String name) {
        return get(name, char.class);
    }

    public Integer getInteger(String name) {
        return get(name, Integer.class);
    }

    public Long getLong(String name) {
        return get(name, Long.class);
    }

    public Double getDouble(String name) {
        return get(name, Double.class);
    }

    public Float getFloat(String name) {
        return get(name, Float.class);
    }

    public Date getDate(String name) {
        return get(name, Date.class);
    }

    public <T> List<T> getList(String name, Class<T> type) {
        return (List<T>) get(name);
    }

    public <T> T populate(Class<T> type) {
        T instance;
        try {
            instance = type.getConstructor().newInstance();
            for (Field field : getAllField(type)) {
                field.setAccessible(true);
                try {
                    field.set(instance, get(field.getName()));
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            }
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException |
                 NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
        return instance;
    }
}
